package com.rub.android.utils

import com.blankj.utilcode.util.SPUtils
import com.facebook.stetho.okhttp3.StethoInterceptor
import com.google.gson.GsonBuilder
import com.rub.android.MainActivity.Companion.context
import com.rub.android.extension.edit
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import rx.Observable
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine


/**
 * 重写retrofit2的Call方法
 */
suspend fun <T> Call<T>.await(): T {
    return suspendCoroutine { continuation ->
        enqueue(object : Callback<T> {
            override fun onFailure(call: Call<T>, t: Throwable) {
                continuation.resumeWithException(t)
            }

            override fun onResponse(call: Call<T>, response: retrofit2.Response<T>) {
                val body = response.body()
                if (body != null) continuation.resume(body)
                else continuation.resumeWithException(RuntimeException("response body is null"))
            }
        })
    }
}


class RetrofitHelper {

    companion object {

        private val TAG = this.javaClass.simpleName

        var BASE_URL = "https://movie.douban.com/j/"
        var WAN_URL = "https://www.wanandroid.com/"
        var GITHUB_URL = "https://api.github.com/"


        private val defaultKey by lazy { "unknown" }

        /**
         * 获取当前选择的源
         */
        fun getCookie(): String {
            return SPUtils.getInstance().getString("is_has_cookie", defaultKey)
        }

        /**
         * 保存当前选择的源
         */
        fun saveCookie(cookieVal: String?) {
            SPUtils.getInstance().put("is_has_cookie", cookieVal)
        }

        /**
         * 是否存在Cookie
         */
        var hasCookie: String
            get() = sharedPreferences.getString("is_has_cookie", "unknown") ?: "unknown"
            set(value) = sharedPreferences.edit { putString("is_has_cookie", value) }
    }

    private var mOkHttpClient: OkHttpClient? = null

    init {
        initOkHttpClient()
    }

    /**
     * 根据传入的baseUrl，和api创建retrofit
     */
    open fun <T> createApi(clazz: Class<T>, baseUrl: String): T {
        val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(mOkHttpClient)
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .addConverterFactory(
                GsonConverterFactory.create(
                    GsonBuilder().registerTypeAdapterFactory(
                        GsonTypeAdapterFactory()
                    ).create()
                )
            )
            .build()
        return retrofit.create(clazz)
    }

    //inline fun <reified T> create():T = create(T::class.java)


    /**
     * 初始化OKHttpClient,设置缓存,设置超时时间,设置打印日志,设置UA拦截器
     * must call proceed() exactly once这是因为你的OkHttpClient.Builder调用的addNetworkInterceptor方法添加的拦截器,
     * 这种方式添加的拦截器里面的Chain只能调用一次proceed方法,如果想调用多次,你的拦截器就要用addInterceptor方法添加,就没问题了
     */
    private fun initOkHttpClient() {
        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY
        if (mOkHttpClient == null) {
            synchronized(RetrofitHelper::class.java) {
                if (mOkHttpClient == null) {
                    //设置Http缓存
                    val cache = Cache(
                        File(
                            context.cacheDir,
                            "HttpCache"
                        ), 1024 * 1024 * 10
                    )
                    mOkHttpClient = OkHttpClient.Builder()
                        .cache(cache)
                        .addInterceptor(interceptor)
                        .addNetworkInterceptor(CacheInterceptor())
                        .addNetworkInterceptor(StethoInterceptor())
                        .retryOnConnectionFailure(true)
                        .connectTimeout(30, TimeUnit.SECONDS)
                        .writeTimeout(20, TimeUnit.SECONDS)
                        .readTimeout(20, TimeUnit.SECONDS)
                        .addInterceptor(UserAgentInterceptor())
                        .addInterceptor(CookiesInterceptor())
                        .build()
                }
            }
        }
    }

    /**
     * 为okhttp添加缓存，这里是考虑到服务器不支持缓存时，从而让okhttp支持缓存
     */
    private class CacheInterceptor : Interceptor {
        @Throws(IOException::class)
        override fun intercept(chain: Interceptor.Chain): Response {
            // 有网络时 设置缓存超时时间1个小时
            val maxAge = 60 * 60
            // 无网络时，设置超时为1天
            val maxStale = 60 * 60 * 24
            var request = chain.request()
            request = if (CommonUtil.isNetworkAvailable(context)) {
                //有网络时只从网络获取
                request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build()
            } else {
                //无网络时只从缓存中读取
                request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build()
            }
            var response = chain.proceed(request)
            response = if (CommonUtil.isNetworkAvailable(context)) {
                response.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public, max-age=$maxAge")
                    .build()
            } else {
                response.newBuilder()
                    .removeHeader("Pragma")
                    .header("Cache-Control", "public, only-if-cached, max-stale=$maxStale")
                    .build()
            }
            return response
        }
    }

    /**
     * 添加UA拦截器，
     */
    private class UserAgentInterceptor : Interceptor {
        @Throws(IOException::class)
        override fun intercept(chain: Interceptor.Chain): Response {
            val originalRequest = chain.request()
            val requestWithUserAgent = originalRequest.newBuilder()
                .removeHeader("User-Agent")
                .addHeader("User-Agent", "OhMyRubRub Android Client/2.1 (rubrub@sina.com)")
                .build()
            return chain.proceed(requestWithUserAgent)
        }
    }


    /**
     * 处理保存cookie
     * https://blog.csdn.net/qqyanjiang/article/details/51264296
     */
    private class CookiesInterceptor : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {

            var response = chain.proceed(chain.request())

            if (response.headers("Set-Cookie").isNotEmpty()) {
                val cookieBuffer = StringBuffer()
                Observable.from(response.headers("Set-Cookie"))
                    .map { s ->
                        val cookieArray = s.split(";".toRegex()).toTypedArray()
                        cookieArray[0]
                    }
                    .subscribe { cookie ->
                        cookieBuffer.append(cookie).append(";")
                    }

                //保存cookie
                saveCookie(cookieBuffer.toString())
                //hasCookie = cookieBuffer.toString()

                logI(TAG, "CookiesInterceptor->> ${cookieBuffer.toString()}")
            }
            /**
             * 缓存存在cookie，设置网络请求参数
             * 判断值不为空，并且不为默认值的时候就设置cookie
             */
            //val cookieVal = hasCookie
            val cookieVal = getCookie()
            logI(TAG, "getCookie=${cookieVal}")
            return if (cookieVal.isNotEmpty() && cookieVal != "unknown") {
                var newRequest = chain.request().newBuilder()
                    //.header("Content-type","application/x-www-form-urlencoded; charset=UTF-8")
                    .header("cookie", cookieVal.substring(0, cookieVal.length - 1))
                    .build()
                chain.proceed(newRequest)
            } else {
                response
            }
        }
    }

    /**
     * 获取token与设置
     * https://blog.csdn.net/ccorg/article/details/62049824
     * https://blog.csdn.net/GD_W001/article/details/94173120
     */

}